Hetzner allows to enter a cloud-init script during server creation. My go-to script is hereunder with some options.
The way this works is : you copy the script during server creation, and it runs it at first boot. Make sure to update your variables. More info on how to do that on the basics/config file handling page.

Does the following :
- Creates a user with sudo rights
- Sets a password and a SSH key for said user
- Setups fail2ban
- Hardens SSH
- Prevents root and password login
- Adds the Helix editor, because I like it :) (You can of course remove it)
CLOUD_INIT_TIMEZONE='timezone, example Europe/Berlin'
CLOUD_INIT_USERNAME='username for the sudo user'
CLOUD_INIT_PASSWORD='hashed password, using the following command : mkpasswd -m sha-512'
CLOUD_INIT_SSH_PUBLIC_KEY='the PUBLIC ssh key (I heavily suggest using ED25519 in order to keep it short)'
#cloud-config
timezone: $CLOUD_INIT_TIMEZONE
users:
- name: $CLOUD_INIT_USERNAME
passwd: $CLOUD_INIT_PASSWORD
ssh_authorized_keys:
- $CLOUD_INIT_SSH_PUBLIC_KEY
groups: sudo #if passwordless : add wheel
shell: /bin/bash
lock_passwd: false
packages:
- fail2ban
- python3-systemd
- hx #adds the Helix editor, not needed for this config to work
package_update: true
package_upgrade: true
write_files:
- content: |
[sshd]
backend = systemd
enabled = true
banaction = iptables-multiport
path: /etc/fail2ban/jail.local
runcmd:
- service fail2ban enable
- sed -i -r 's/^#?PermitRootLogin.*$/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?PasswordAuthentication.*$/PasswordAuthentication no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?PermitEmptyPasswords.*$/PermitEmptyPasswords no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?PubkeyAuthentication.*$/PubkeyAuthentication yes/' /etc/ssh/sshd_config
- sed -i -r 's/^#?StrictModes.*$/StrictModes yes/' /etc/ssh/sshd_config
- sed -i -r 's/^#?MaxAuthTries.*$/MaxAuthTries 2/' /etc/ssh/sshd_config
- sed -i -r 's/^#?StrictModes.*$/StrictModes yes/' /etc/ssh/sshd_config
- sed -i -r 's/^#?UsePAM.*$/UsePAM no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?X11Forwarding.*$/X11Forwarding no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?AllowAgentForwarding.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config
- sed -i -r 's/^#?AllowTcpForwarding.*$/AllowTcpForwarding no/' /etc/ssh/sshd_config
- service sshd restart
If you want to prevent the sudo prompt for password (not recommended), add the user to the group wheel in addition to the group sudo (leave a blank space between the groups : sudo wheel). Then add the following line at the end of the config script :
- sed -i -e '$a%wheel ALL=(ALL) NOPASSWD: ALL' /etc/sudoers
add the following line just before the - service sshd restart :
- sed -i '$a AllowUsers $CLOUD_INIT_USERNAME' /etc/ssh/sshd_config
If you want to add more than one user, separate them with a space, as such : AllowUsers Bob Alice
add the following lines at the end of the config file :
- install -m 0755 -d /etc/apt/keyrings
- curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
- chmod a+r /etc/apt/keyrings/docker.asc
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
- apt update
- apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin